 /* Copyright 2010-2013 Rob Landley <rob@landley.net> */
 
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int main(int argc, char *argv[])
 {
 	uint64_t hz, periods[] = {1000, 1000000};
 	char *names[] = {"MSEC", "USEC"};
 	FILE *file;
 	int i, j;
 
 	if (argc != 3 || (hz = atol(argv[1])) < 1
 	    || !(file = !strcmp(argv[2], "-") ? stdout : fopen(argv[2], "w")))
 	{
 		fprintf(stderr, "Usage: mktimeconst HZ FILENAME\n\n");
 		fprintf(stderr, "Generate a header file with constants to convert between\n");
 		fprintf(stderr, "decimal HZ timer ticks and milisecond or microsecond delays,\n");
 		fprintf(stderr, "using reciprocal multiplication to avoid 64 bit division.\n");
 		exit(1);
 	}
 
 	fprintf(file,
 		"/* Automatically generated by kernel/mktimeconst */\n"
 		"/* Conversion constants for HZ == %"PRIu64" */\n\n"
 		"#ifndef __KERNEL_TIMECONST_H\n"
 		"#define __KERNEL_TIMECONST_H\n\n"
 		"#include <linux/param.h>\n"
 		"#include <linux/types.h>\n\n"
 		"#if HZ != %"PRIu64"\n"
 		"#error \"include/generated/timeconst.h has the wrong HZ value!\"\n"
 		"#endif\n\n", hz, hz);
 
 	/* Repeat for MSEC and USEC */
 
 	for (i = 0; i < 2; i++) {
 		uint64_t gcd, period;
 
 		/* Find greatest common denominator using Euclid's algorithm. */
 
 		gcd = hz;
 		period = periods[i];
 		while (period) {
 			uint64_t temp = gcd % period;
 			gcd = period;
 			period = temp;
 		}
 
 		/* Output both directions (HZ_TO_PERIOD and PERIOD_TO_HZ) */
 
 		for (j = 0; j < 2; j++) {
 			char name[16];
 			uint64_t from = j ? periods[i] : hz;
 			uint64_t to = j ? hz : periods[i];
 			uint64_t mul32 = 0, adj32 = 0, shift = 0;
 
 			sprintf(name, j ? "%s_TO_HZ" : "HZ_TO_%s", names[i]);
 
 			/* Figure out what shift value gives 32 significant
 			   bits of MUL32 data.  (Worst case to=1 from=1000000
 			   uses 52 bits, to<<shift won't overflow 64 bit math.)
 			*/
 
 			for (;;) {
 				mul32 = ((to << shift) + from - 1) / from;
 				if (mul32 >= (1UL<<31))
 					break;
 				shift++;
 			}
 
 			/* ADJ32 is is just (((FROM/GCD)-1)<<SHIFT)/(FROM/GCD)
 			   but this can overflow 64 bit math (examples, HZ=24
 			   or HZ=122).  Worst case scenario uses 32+20+20=72
 			   bits.  Workaround: split off bottom 32 bits and
 			   reassemble after calculation (32+64=96 bits). */
 
 			adj32 = from / gcd;
 
 			if (shift > 32) {
 				uint64_t upper, lower;
 
 				upper = (adj32 - 1) << (shift - 32);
 				lower = (upper % adj32) << 32;
 				adj32 = ((upper/adj32) << 32) + (lower/adj32);
 			} else
 				adj32 = ((adj32 - 1) << shift) / adj32;
 
 			/* Emit the constants into the header file. */
 
 			fprintf(file, "#define %s_MUL32\tU64_C(0x%"PRIx64")\n",
 				name, mul32);
 			fprintf(file, "#define %s_ADJ32\tU64_C(0x%"PRIx64")\n",
 				name, adj32);
 			fprintf(file, "#define %s_SHR32\t%"PRIu64"\n",
 				name, shift);
 			fprintf(file, "#define %s_NUM\t\tU64_C(%"PRIu64")\n",
 				name, to/gcd);
 			fprintf(file, "#define %s_DEN\t\tU64_C(%"PRIu64")\n\n",
 				name, from/gcd);
 		}
 	}
 	fprintf(file, "#endif /* __KERNEL_TIMECONST_H */\n");
 
 	/* Notice if the disk fills up. */
 
 	fflush(file);
 	return ferror(file);
 }
